<script lang="tsx">
import {
  defineComponent,
  ref,
  computed,
  type PropType,
  type ExtractPropTypes,
  unref,
  inject,
  watch,
  toRaw,
  reactive,
  provide
} from 'vue'
import {
  ElTable,
  ElTableColumn,
  ElPagination,
  paginationProps,
  ElIcon,
  ElLink,
  ElForm
} from 'element-plus'
import { cloneDeep, isFunction, merge, omit } from 'lodash-es'
import {
  $AONE_LAN,
  getValOrFnResult,
  type BaseType,
  type SimpleKeyValueObject,
  copyText
} from '../form/utils'
import oFormFactory, {
  type iFormColumnType,
  type FormColumnSupportType
} from 'oneui/form/factory.vue'
import { oLink } from '../form/index'
import { DocumentCopy, View, Edit } from '@element-plus/icons-vue'

export interface iPaggingDataType {
  currentPage: number
  pageSize: number
  total: number
  pageSizes: Array<number>
}
export interface iTableDataType {
  items: Array<SimpleKeyValueObject>
  total: number
}
export interface iTableColumnType extends iFormColumnType {
  width?: number
  fixed?: string
  groupUniqueKey?: string
  align?: string
  copy?: boolean | Function
  view?: Function
  edit?: Function
  sortable?: boolean
  time?: boolean | Function
  picture?: boolean | Function
  tooltip?: boolean | Function
  money?: boolean | Function
  integer?: boolean | Function
  summary?: boolean | Function
}
export interface iParamType extends SimpleKeyValueObject {
  currentPage: number
  pageSize: number
}
export interface iTableOptionsProps {
  columns: Array<iTableColumnType>
  loadImmediate?: boolean
  pageApiPromise?: (p: iParamType) => Promise<SimpleKeyValueObject>
  requestHandler?: Function
  responseHandler?: Function
  options?: Array<BaseType>
  pagination?: boolean
  showHeader?: boolean
  currentPage?: number
  pageSize?: number
  pageSizes?: Array<number>
  tableInForm?: boolean
}
export const oTableProps = {
  tableOptions: {
    required: true,
    type: Object as PropType<iTableOptionsProps>
  }
}
export type oTablePropsType = ExtractPropTypes<typeof oTableProps>
export default defineComponent({
  components: {
    ElTable,
    ElTableColumn,
    ElPagination,
    oFormFactory,
    ElLink,
    oLink,
    DocumentCopy,
    View,
    Edit
  },
  props: oTableProps,
  setup(props: oTablePropsType, context) {
    const paggingData = inject<iPaggingDataType>('paggingData')!
    const tableData = inject<iTableDataType>('tableData')!
    const eventData = inject<SimpleKeyValueObject>('eventData')!
    const formData = inject<SimpleKeyValueObject>('formData')!

    const tableOptionsSync = computed(() => {
      const tableOptions = merge(
        {
          loadImmediate: true,
          requestHandler: (c: SimpleKeyValueObject) => c,
          responseHandler: (c: SimpleKeyValueObject) => c,
          columns: new Array<iTableColumnType>(),
          tableInForm: false
        },
        unref(props.tableOptions)
      )
      return tableOptions
    })

    const columnsSync = computed(() => {
      return tableOptionsSync.value.columns
        .filter((c) => {
          if (!c) return false
          return getValOrFnResult(c.visiable) !== false
        })
        .map((c) => {
          return merge(
            {
              align: 'center',
              zero: true,
              perm: 'true'
            },
            c
          )
        })
    })

    // 如果表格列有表单控件，input，select，radio，switch等，就再table外部包裹一层form
    // const isExistFormCtrl = columnsSync.value.find((it) =>
    //   ['input', 'select', 'radio', 'switch'].includes(`${it.comtype}`)
    // )
    // tableOptionsSync.value.tableInForm = !!isExistFormCtrl

    const paggingSync = computed(() => {
      return {
        pageSizes: paggingData.pageSizes,
        total: tableData.total,
        background: true,
        layout: 'total, sizes, prev, pager, next, jumper',
        onCurrentChange(val: number) {
          paggingData.currentPage = val
          eventData.search = true
        },
        onSizeChange(val: number) {
          paggingData.currentPage = 1
          paggingData.pageSize = val
          eventData.search = true
        }
      }
    })

    // 监听search
    watch(
      () => eventData.search,
      () => {
        if (!eventData.search) return
        const { requestHandler, pageApiPromise, responseHandler } = tableOptionsSync.value
        const cloneParam = cloneDeep(toRaw(formData))
        const param = requestHandler({
          ...cloneParam,
          currentPage: paggingData.currentPage,
          pageSize: paggingData.pageSize
        }) as iParamType

        pageApiPromise!(param).then(
          (res) => {
            res = responseHandler(res)
            // 支持返回 items 和 list
            tableData.items = (res.items || res.list) as Array<SimpleKeyValueObject>
            tableData.total = res.total as number
            eventData.search = false
          },
          (error: Error) => {
            console.error(error)
            eventData.search = false
          }
        )
      }
    )

    // 立即请求
    watch(
      () => tableOptionsSync.value.loadImmediate,
      (v) => {
        if (v) {
          eventData.search = true
        }
      },
      { immediate: true }
    )

    const renderTableColumns = () => {
      const columnsList: Array<JSX.Element> = []
      columnsSync.value.forEach((originColumn) => {
        const renderColumnJsx = (): JSX.Element => {
          const buildFormOptions = (
            scope: SimpleKeyValueObject,
            data: iTableColumnType,
            option: SimpleKeyValueObject
          ) => {
            const row = scope.row as SimpleKeyValueObject
            const comtype = data.comtype || 'text'
            const renderFooter = (inProps: iFormColumnType) => {
              const rightOperatorList: Array<JSX.Element | null> = []
              const buildInnerButton = (
                jsx: JSX.Element,
                tag: Function | boolean | undefined,
                callback?: Function
              ) => {
                const fn = tag ? (isFunction(tag) ? tag : callback) : null
                return fn ? (
                  <oLink underline={false} formData={{}} prop="prop">
                    <jsx onClick={() => fn(row, data)} />
                  </oLink>
                ) : null
              }
              // 复制按钮
              rightOperatorList.push(
                buildInnerButton(
                  <ElIcon>
                    <DocumentCopy />
                  </ElIcon>,
                  data.copy,
                  () => copyText(row[data.prop!] as string)
                )
              )
              // 查看按钮
              rightOperatorList.push(
                buildInnerButton(
                  <ElIcon>
                    <View />
                  </ElIcon>,
                  data.view
                )
              )
              // 编辑按钮
              rightOperatorList.push(
                buildInnerButton(
                  <ElIcon>
                    <Edit />
                  </ElIcon>,
                  data.edit
                )
              )
              return rightOperatorList.filter(Boolean)
            }
            const formItemClassNameArray = ['one-nopadding']
            if (!data.labelWidth || data.labelWidth == '0px') {
              formItemClassNameArray.push('one-form-item-nolabel')
            }
            return merge(
              {
                columns: [
                  {
                    value: row[data.prop!],
                    ...omit(data, ['label']),
                    row: row,
                    comtype: comtype,
                    renderHeader: null,
                    renderFooter,
                    formItemClassName: formItemClassNameArray.join(' ')
                  }
                ]
              },
              {
                existFactoryForm: !!props.tableOptions?.tableInForm // 表格中每个cell不显示为form
              },
              data
            )
          }
          // 是否全选列
          if (originColumn.type == 'selection') {
            return <el-table-column {...originColumn} />
          }
          return (
            <el-table-column
              {...originColumn}
              v-slots={{
                header: () => (
                  <oFormFactory
                    formOptions={buildFormOptions(
                      { row: {} },
                      {
                        value: getValOrFnResult(originColumn.label)
                      },
                      {
                        head: true
                      }
                    )}
                  />
                ),
                default: (scope: SimpleKeyValueObject) => {
                  const formData = reactive(scope.row as SimpleKeyValueObject)
                  return (
                    <oFormFactory
                      formOptions={buildFormOptions(scope, originColumn, {
                        body: true
                      })}
                      formData={formData}
                    />
                  )
                }
              }}
            ></el-table-column>
          )
        }
        columnsList.push(renderColumnJsx())
      })
      return columnsList
    }
    return () => {
      let tableJsx = (
        <ElTable class={['one-table']} border data={tableData.items}>
          {renderTableColumns()}
        </ElTable>
      )
      // 表格外部嵌套一层form，常用有多行表格动态修改数据验证
      if (tableOptionsSync.value.tableInForm) {
        tableJsx = (
          <ElForm class={['one-form']} model={formData}>
            {tableJsx}
          </ElForm>
        )
      }
      return [
        tableJsx,
        <ElPagination
          class={['one-pagging']}
          v-model:current-page={paggingData.currentPage}
          v-model:page-size={paggingData.pageSize}
          {...paggingSync.value}
        />
      ]
    }
  }
})
</script>
<style lang="scss">
.one-table {
  width: 100%;
}
</style>
